package com.xinsoft.service.impl;

import cn.afterturn.easypoi.excel.ExcelImportUtil;
import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.entity.dto.ExcelErrRowDTO;
import com.xinsoft.entity.dto.SysClientDTO;
import com.xinsoft.entity.dto.SysClientImportDTO;
import com.xinsoft.entity.dto.SysClientPageParam;
import com.xinsoft.entity.po.*;
import com.xinsoft.entity.vo.SysClientVo;
import com.xinsoft.mapper.SysClientMapper;
import com.xinsoft.service.*;
import com.xinsoft.utils.ExcelUtils;
import com.xinsoft.utils.TokenUtil;
import com.xinsoft.validator.ValidatorUtils;
import org.apache.commons.lang.StringUtils;
import org.json.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* @author hsm
* @description 针对表【sys_client(客户)】的数据库操作Service实现
* @createDate 2023-05-23 13:04:01
*/
@Service
public class SysClientServiceImpl extends ServiceImpl<SysClientMapper, SysClient>
    implements SysClientService{


    @Resource
    private SysClientLinkmanService sysClientLinkmanService;

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysDictionaryService sysDictionaryService;

    @Resource
    private SysFileHisService sysFileHisService;

    @Resource
    private SysClientLevelService sysClientLevelService;

    @Resource
    private SysDeptService sysDeptService;


    @Override
    public SysClient addSysClient(SysClientDTO sysClientDTO) {
        // 判断客户名称是否重复
        QueryWrapper<SysClient> sysClientQuery = new QueryWrapper<>();
        sysClientQuery.select("id");
        sysClientQuery.eq("client_name",sysClientDTO.getClientName());
        List clients = this.list(sysClientQuery);

        if(CollectionUtil.isNotEmpty(clients)){
            throw new BDException("操作失败，客户名称重复！");
        }

        //判断客户code是否重复
        QueryWrapper<SysClient> sysClientQueryByCode = new QueryWrapper<>();
        sysClientQueryByCode.select("id");
        sysClientQueryByCode.eq("client_code",sysClientDTO.getClientCode());
        List clients2 = this.list(sysClientQueryByCode);
        if(CollectionUtil.isNotEmpty(clients2)){
            throw new BDException("操作失败，客户编号重复！");
        }

        //判断客户社会信用统一码是否重复
        QueryWrapper<SysClient> sysClientQueryByUscc = new QueryWrapper<>();
        sysClientQueryByUscc.select("id");
        sysClientQueryByUscc.eq("uscc",sysClientDTO.getUscc());
        List clients3 = this.list(sysClientQueryByUscc);
        if(CollectionUtil.isNotEmpty(clients3)){
            throw new BDException("操作失败，客户社会统一信用代码重复！");
        }

        SysClient client = new SysClient();
        BeanUtils.copyProperties(sysClientDTO,client);
        client.setAuditStatus(0);//未审核
        this.save(client);

        //按照之前表设计将联系人保存在clientLinkman表中
        if(CollectionUtil.isNotEmpty(sysClientDTO.getSysClientLinkmanList())){
            for (SysClientLinkman sysClientLinkman : sysClientDTO.getSysClientLinkmanList()) {
                sysClientLinkman.setClientId(client.getId());
            }
            sysClientLinkmanService.saveBatch(sysClientDTO.getSysClientLinkmanList());//保存联系人
        }

        return client;

    }

    @Override
    public SysClient editSysClient(SysClientDTO sysClientDTO) {

        //判断是否可以修改//禁用状态且未审核
        SysClient client = this.getById(sysClientDTO.getId());
        if(Objects.equals(client.getAuditStatus(),1)){
            throw new BDException("操作失败，客户已审核无法修改！");
        }

        // 判断客户名称是否重复
        QueryWrapper<SysClient> sysClientQuery = new QueryWrapper<>();
        sysClientQuery.select("id");
        sysClientQuery.eq("client_name",sysClientDTO.getClientName());
        sysClientQuery.ne("id",sysClientDTO.getId());
        List clients = this.list(sysClientQuery);

        if(CollectionUtil.isNotEmpty(clients)){
            throw new BDException("操作失败，客户名称重复！");
        }

        //判断客户社会信用统一码是否重复
        QueryWrapper<SysClient> sysClientQueryByUscc = new QueryWrapper<>();
        sysClientQueryByUscc.select("id");
        sysClientQueryByUscc.eq("uscc",sysClientDTO.getUscc());
        sysClientQueryByUscc.ne("id",sysClientDTO.getId());
        List clients3 = this.list(sysClientQueryByUscc);
        if(CollectionUtil.isNotEmpty(clients3)){
            throw new BDException("操作失败，客户社会统一信用代码重复！");
        }

        BeanUtils.copyProperties(sysClientDTO,client);
        client.setClientCode(null);
        client.setAuditStatus(0);//未审核
        // 保存客户
        this.updateById(client);

        //按照之前表设计将联系人保存在clientLinkman表中
        //移除之前的数据
        QueryWrapper linkManQuery = new QueryWrapper();
        linkManQuery.eq("do_delete",0);
        linkManQuery.eq("client_id",client.getId());
        sysClientLinkmanService.remove(linkManQuery);
        // 保存联系人
        if(CollectionUtil.isNotEmpty(sysClientDTO.getSysClientLinkmanList())){
            for (SysClientLinkman sysClientLinkman : sysClientDTO.getSysClientLinkmanList()) {
                sysClientLinkman.setClientId(client.getId());
            }
            sysClientLinkmanService.saveBatch(sysClientDTO.getSysClientLinkmanList());//保存联系人
        }
        return client;
    }

    @Override
    public void del(List<Integer> ids) {
        QueryWrapper<SysClient> sysUserQuery1 = new QueryWrapper<>();
        sysUserQuery1.eq("client_status",1);//启用
        sysUserQuery1.in("id",ids);
        List<SysClient> clients = this.list(sysUserQuery1);
        //判断是否已启用
        if(CollectionUtil.isNotEmpty(clients)){
            throw new BDException("操作失败，"+clients.get(0).getClientName()+"已启用无法删除！");
        }

        QueryWrapper<SysClient> sysUserQuery2 = new QueryWrapper<>();
        sysUserQuery2.eq("audit_status",1);//启用
        List<SysClient> clients2 = this.list(sysUserQuery2);
        //判断是否已启用
        if(CollectionUtil.isNotEmpty(clients)){
            throw new BDException("操作失败，"+clients2.get(0).getClientName()+"已审核无法删除！");
        }

        // 删除
        removeByIds(ids);

        // 删除联系人
        QueryWrapper userRoleQuery = new QueryWrapper();
        userRoleQuery.in("client_id",ids);
        sysClientLinkmanService.remove(userRoleQuery);
    }

    @Override
    public SysClientDTO getSysClient(Integer id) {
        SysClient client = this.getById(id);
        SysClientDTO clientDTO = new SysClientDTO();
        BeanUtils.copyProperties(client,clientDTO);
        clientDTO.setId(client.getId());

        //获取业务员名称
        SysUser belongUser = sysUserService.getById(client.getBelongUserId());
        if(belongUser!=null){
            clientDTO.setBelongUserName(belongUser.getRealName());
            //获取业务员部门名称
            SysDept dept = sysDeptService.getById(belongUser.getDeptId());
            if(dept!=null){
                clientDTO.setBelongDeptName(dept.getDeptName());
            }
        }

        //获取类型名称
        SysDictionary dictionary = sysDictionaryService.getById(client.getType());
        if(dictionary!=null){
            clientDTO.setTypeName(dictionary.getTypeName());
        }

        //获取创建人名称
        SysUser create = sysUserService.getById(client.getCreateBy());
        if(create!=null){
            clientDTO.setCreateByName(create.getRealName());
        }
        //获取审核人名称
        SysUser audit = sysUserService.getById(client.getAuditId());
        if(audit!=null){
            clientDTO.setAuditName(audit.getRealName());
        }

        //获取客户等级名称
        SysClientLevel sysClientLevel = sysClientLevelService.getById(client.getLevelId());
        if(sysClientLevel!=null) {
            clientDTO.setLevelName(sysClientLevel.getLevelName());
        }
        //获取联系人list
        QueryWrapper userRoleQuery = new QueryWrapper();
        userRoleQuery.in("client_id",clientDTO.getId());
        clientDTO.setSysClientLinkmanList(sysClientLinkmanService.list(userRoleQuery));
        return clientDTO;
    }

    @Override
    public void enable(List<Integer> ids) {
        UpdateWrapper<SysClient> sysUserUpdateQuery = new UpdateWrapper<>();
        sysUserUpdateQuery.set("client_status",1);//启用
        sysUserUpdateQuery.in("id",ids);
        sysUserUpdateQuery.eq("do_delete",0);
        this.update(sysUserUpdateQuery);
    }

    @Override
    public void disable(List<Integer> ids) {
        UpdateWrapper<SysClient> sysUserUpdateQuery = new UpdateWrapper<>();
        sysUserUpdateQuery.set("client_status",0);//禁用
        sysUserUpdateQuery.in("id",ids);
        sysUserUpdateQuery.eq("do_delete",0);
        this.update(sysUserUpdateQuery);
    }

    @Override
    public void audit(List<Integer> ids) {
        UpdateWrapper<SysClient> sysUserUpdateQuery = new UpdateWrapper<>();
        sysUserUpdateQuery.set("audit_status",1);//审核
        sysUserUpdateQuery.set("audit_id", TokenUtil.getUserId());//设置审核人
        sysUserUpdateQuery.in("id",ids);
        sysUserUpdateQuery.eq("do_delete",0);
        this.update(sysUserUpdateQuery);
    }

    @Override
    public void deAudit(List<Integer> ids) {
        UpdateWrapper<SysClient> sysUserUpdateQuery = new UpdateWrapper<>();
        sysUserUpdateQuery.set("audit_status",0);//反审核
        sysUserUpdateQuery.set("audit_id", TokenUtil.getUserId());//设置审核人
        sysUserUpdateQuery.in("id",ids);
        sysUserUpdateQuery.eq("do_delete",0);
        this.update(sysUserUpdateQuery);

    }

    @Override
    public JSONObject importExcel(MultipartFile multipartFile) throws IOException {
        // 初始化错误行信息list，用来记录导入失败的rowNum
        List<ExcelErrRowDTO> errRowDOs = new ArrayList<>();

        // 对excel是否为空进行check
        if (multipartFile.isEmpty()) {
            throw new BDException("导入失败，请选择文件！");
        }

        //设置excel参数
        ImportParams params = new ImportParams();
        params.setTitleRows(1);
        params.setHeadRows(1);
        List<SysClientImportDTO> sysClientList;
        List<SysClient> sysClients = CollectionUtil.newArrayList();

        // 解析excel中的行，放到sysClientList中
        try {
            // 解析excel
                sysClientList = ExcelImportUtil.importExcel(multipartFile.getInputStream(), SysClientImportDTO.class, params);
        } catch (Exception e) {
            throw new BDException("导入失败，文件内容解析错误！");
        }
        JSONObject result = new JSONObject();

        //校验
        if (sysClientList.size() > 0) {
            //取出excel和db中所有重复的name
            List<String> excelClientNames = sysClientList.stream()
                    .map(SysClientImportDTO::getClientName)
                    .collect(Collectors.toList()); // 获取excel中所有的username
            List<String> dbClientNames = this.getAllClientName();//获取系统中所有的ClientName
            List<String> duplicateClientNames = new ArrayList<>(); // 存放存在重复的clientName，用于定位重复存放存在重复的clientName的行

            if (dbClientNames.size() > 0 && excelClientNames.size() > 0) {
                dbClientNames.addAll(excelClientNames);//合并
                duplicateClientNames = ExcelUtils.getDuplicateElements(dbClientNames);//取出存在重复的username
            }

            //取出excel和db中所有重复的code
            List<String> excelClientCodes = sysClientList.stream()
                    .map(SysClientImportDTO::getClientCode)
                    .collect(Collectors.toList()); // 获取excel中所有的username
            List<String> dbClientCodes = this.getAllClientCode();//获取系统中所有的Clientcode
            List<String> duplicateClientCodes = new ArrayList<>(); // 存放存在重复的Clientcode，用于定位重复存放存在重复的clientName的行

            if (dbClientCodes.size() > 0 && excelClientCodes.size() > 0) {
                dbClientCodes.addAll(excelClientCodes);//合并
                duplicateClientCodes = ExcelUtils.getDuplicateElements(dbClientCodes);//取出存在重复的username
            }

            //取出excel和db中所有重复的uscc
            List<String> excelClientUsccs = sysClientList.stream()
                    .map(SysClientImportDTO::getUscc)
                    .collect(Collectors.toList()); // 获取excel中所有的username
            List<String> dbClientUsccs = this.getAllClientUscc();//获取系统中所有的ClientUscc
            List<String> duplicateClientUsccs = new ArrayList<>(); // 存放存在重复的ClientUscc，用于定位重复存放存在重复的supplierName的行

            if (dbClientUsccs.size() > 0 && excelClientUsccs.size() > 0) {
                dbClientUsccs.addAll(excelClientUsccs);//合并
                duplicateClientUsccs = ExcelUtils.getDuplicateElements(dbClientUsccs);//取出存在重复的username
            }

            // 服务类型(字典 client_type)
            List<SysDictionary> dictionaryList =  sysDictionaryService.getDictByTypeCode("client_type");
            Map<String, Integer> clientTypeMap = dictionaryList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));

            // 服务类型(字典 client_type)
            List<SysDictionary> paymentList =  sysDictionaryService.getDictByTypeCode("type_of_payment");
            Map<String, Integer> paymentMap = paymentList.stream()
                    .collect(Collectors.toMap(SysDictionary::getDicName, SysDictionary::getId, (v1, v2) -> v2));


            // 人员
            List<SysUser> userList = sysUserService.list();
            Map<String, SysUser> userMap = userList.stream()
                    .collect(Collectors.toMap(SysUser::getRealName, Function.identity(), (v1, v2) -> v2));

            // 客户等级
            List<SysClientLevel> clientList = sysClientLevelService.list();
            Map<String, Integer> levelMap = clientList.stream()
                    .collect(Collectors.toMap(SysClientLevel::getLevelName, SysClientLevel::getId, (v1, v2) -> v2));


            int index = 1;
            for (SysClientImportDTO sysClientDTO : sysClientList) {
                index ++;
                // check
                StringBuilder stringBuilder = new StringBuilder();
                ExcelErrRowDTO excelErrRowDO= new ExcelErrRowDTO();

                // 参数校验
                stringBuilder.append(ValidatorUtils.validateExcel(sysClientDTO));

                // 检验clientName 是否重复
                if(duplicateClientNames.contains(sysClientDTO.getClientName())){
                    stringBuilder.append("客户已经存在，请勿重复！");
                }
                // 检验clientCode 是否重复
                if(duplicateClientCodes.contains(sysClientDTO.getClientCode())){
                    stringBuilder.append("客户编号已经存在，请勿重复！");
                }

                // 检验supplierUscc 是否重复
                if(duplicateClientUsccs.contains(sysClientDTO.getUscc())){
                    stringBuilder.append("客户社会统一信用代码已经存在，请勿重复！");
                }

                // 设置 所属业务员
                if(StringUtils.isNotEmpty(sysClientDTO.getBelongUserName())){
                    SysUser user = userMap.get(sysClientDTO.getBelongUserName());
                    if(user==null){
                        stringBuilder.append("所属业务员:"+sysClientDTO.getBelongUserName()+",在系统中不存在！");
                    }else{
                        sysClientDTO.setBelongUserId(user.getId());
                        sysClientDTO.setBelongDeptId(user.getDeptId());
                    }
                }

                // 服务类型
                if(StringUtils.isNotEmpty(sysClientDTO.getTypeName())){
                    Integer typeId = clientTypeMap.get(sysClientDTO.getTypeName());
                    if(typeId==null){
                        stringBuilder.append("服务类型:"+sysClientDTO.getTypeName()+",在系统中不存在！");
                    }
                    sysClientDTO.setType(typeId);
                }

                // 付款类型
                if(StringUtils.isNotEmpty(sysClientDTO.getDefaultPayTypeName())){
                    Integer paymentId = paymentMap.get(sysClientDTO.getDefaultPayTypeName());
                    if(paymentId==null){
                        stringBuilder.append("付款类型:"+sysClientDTO.getDefaultPayTypeName()+",在系统中不存在！");
                    }
                    sysClientDTO.setDefaultPayType(paymentId);
                }

                // 客户等级
                if(StringUtils.isNotEmpty(sysClientDTO.getLevelName())){
                    Integer levelId = levelMap.get(sysClientDTO.getLevelName());
                    if(levelId==null){
                        stringBuilder.append("客户等级:"+sysClientDTO.getLevelName()+",在系统中不存在！");
                    }
                    sysClientDTO.setLevelId(levelId);
                }

                // 状态 0:禁用，1:正常
                if(StringUtils.equals(sysClientDTO.getClientStatusName(),"启用")){
                    sysClientDTO.setClientStatus(1);
                }else{
                    sysClientDTO.setClientStatus(0);
                }

                // 是否启用信用管理 0：否 1：是
                if(StringUtils.equals(sysClientDTO.getDoCreditName(),"是")){
                    sysClientDTO.setDoCredit(1);
                }else{
                    sysClientDTO.setDoCredit(0);
                }

                // 将错误行信息保存到list
                String errMsg = stringBuilder.toString();
                if(StringUtils.isNotEmpty(errMsg)){
                    excelErrRowDO.setRowIndex(index);
                    excelErrRowDO.setErrMessage(errMsg);
                    errRowDOs.add(excelErrRowDO);
                    continue;
                }
                //保存
                SysClient client = new SysClient();
                BeanUtils.copyProperties(sysClientDTO,client);
                sysClients.add(client);
            }
            //批量保存
            saveBatch(sysClients);
            String errFileUrl = ExcelUtils.exportErrRows(errRowDOs,multipartFile,sysFileHisService);

            result.put("errFileUrl",errFileUrl);
            return result;
        }
        return result;
    }

    @Override
    public List<SysClientVo> findListByParam(SysClientPageParam param) {
        //不分页
        List<SysClientVo> clients = this.baseMapper.findListByParam(param);
        //返回值
        return clients;
    }

    @Override
    public void insertOrUpdateBatch(List<SysClient> sysClientList) {
        baseMapper.insertOrUpdateBatch(sysClientList);
    }

    @Override
    public IPage<SysClientVo> findPageListByParam(SysClientPageParam param) {
        //分页
        Page<SysClientVo> page = new Page<SysClientVo>(param.getCurrentPage(), param.getPageSize());
        //查询分页
        IPage<SysClientVo> clients = this.baseMapper.findListByParam(page, param);
        //返回值
        return clients;
    }

    private List<String> getAllClientName() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("client_name");
        List<SysClient> userList = this.list();
        List<String> usernames = userList.stream().map(SysClient::getClientName).collect(Collectors.toList());
        return usernames;
    }

    private List<String> getAllClientCode() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("client_code");
        List<SysClient> userList = this.list();
        List<String> codes = userList.stream().map(SysClient::getClientCode).collect(Collectors.toList());
        return codes;
    }

    private List<String> getAllClientUscc() {
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.select("uscc");
        List<SysClient> userList = this.list();
        List<String> usccs = userList.stream().map(SysClient::getUscc).collect(Collectors.toList());
        return usccs;
    }

}




